﻿using System;
using System.Collections.Generic;
using SMLib.Automata.IA;
using SMLib.Automata.MM;
using SMLib.Automata.Base;

namespace MBT.Conformance
{
    /// <summary>
    /// Wrap a Mealy machine system as an IA system: So, we can gan use IA testing
    /// engine for Mealy machines.
    /// It requires forward and backward translation from a Mealy machine into an IA
    /// </summary>
    public class MealyWrappedInIA : IBlackBox_IA
    {
        IBlackBox_MM SUT;
        bool actionRecieved;
        ISymbol lastOutput;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="SUT">the mealy machine SUT</param>
        public MealyWrappedInIA(IBlackBox_MM SUT)
        {
            lastOutput = null;
            this.SUT = SUT;
            this.actionRecieved = false;
        }

        #region IBlackBox_IOLTS Members

        /// <summary>
        /// Reset to inital state
        /// </summary>
        public void Reset()
        {
            SUT.Reset();
        }

        /// <summary>
        /// Perform a -controllable- action
        /// If it is enabled, ...
        /// </summary>
        /// <param name="input">the action symbol</param>
        public void Perform(ISymbol input)
        {
            lastOutput = SUT.Step(input);
            if (lastOutput == null)
            {
                actionRecieved = false;
                throw new NotEnabledActionException("");
            }
            else
            {
                actionRecieved = true;
            }
        }

        /// <summary>
        /// Is there any event available?
        /// </summary>
        /// <returns>true if yes, false if no</returns>
        public bool EventAvailable()
        {
            return actionRecieved;
        }

        /// <summary>
        /// Obsererve the last seen event (and consume it)
        /// </summary>
        /// <returns>the last seen event (exception if no event is available)</returns>
        public ISymbol Event()
        {
            if (actionRecieved)
            {
                actionRecieved = false;
                return lastOutput;
            }
            else
            {
                //throw new Exception("No event is available!");
				return null;
            }
        }

        #endregion

        /// <summary>
        /// Translate back the executed trace on IA into Mealy executed trace
        /// </summary>
        /// <param name="executedTraceOnIOLTS">the executed trace on IA<remarks>(it can also be IOLTS_Step)</remarks></param>
        /// <returns>the computed executed trace on Mealy machine</returns>
        public List<PairOfSymbols> ExecutedTraceOnMealy(List<ISymbol> executedTraceOnIOLTS)
        {
            if (executedTraceOnIOLTS.Count % 2 != 0)
            {
                throw new Exception();
            }

            List<PairOfSymbols> mealyExecutedTrace = new List<PairOfSymbols>();
            for (int i = 0; i < executedTraceOnIOLTS.Count; i += 2)
            {
                mealyExecutedTrace.Add(new PairOfSymbols(executedTraceOnIOLTS[i], executedTraceOnIOLTS[i + 1]));
            }
            return mealyExecutedTrace;
        }

        /// <summary>
        /// 
        /// </summary>
        public Alphabet InputAlphabet
        {
            get { return this.SUT.InputAlphabet; }
        }

    }
}
